package thu.cs.segroup.agent;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Queue;
import java.util.Set;
import java.util.ArrayDeque;

import thu.cs.segroup.agent.behaviour.CommonSendObjMsgBehav;
import thu.cs.segroup.agent.behaviour.CoorGernerateRunnerBehav;
import thu.cs.segroup.agent.behaviour.CoorInterpreter;
import thu.cs.segroup.agent.behaviour.CoorParseTaskBehav;
import thu.cs.segroup.entity.RunnerState;
import thu.cs.segroup.entity.TestTask;
import thu.cs.segroup.entity.TestSuite;
import thu.cs.segroup.entity.TestCase;
import thu.cs.segroup.exception.CaseNameConflictException;
import thu.cs.segroup.gui.MainFrame;
import thu.cs.segroup.rule.RuleEngine;
import thu.cs.segroup.test.ReceiveMsgBehavTest;
import thu.cs.segroup.test.SendMsgBehavTest;
import thu.cs.segroup.util.Constants;
import jade.content.ContentElement;
import jade.content.lang.sl.SLCodec;
import jade.content.onto.basic.Action;
import jade.content.onto.basic.Result;
import jade.core.Agent;
import jade.core.Location;
import jade.domain.JADEAgentManagement.QueryPlatformLocationsAction;
import jade.domain.mobility.MobilityOntology;
import jade.lang.acl.ACLMessage;

public class Coordinator extends Agent {

	private Map<String, Set> wsTestCases;
	private TestSuite suite;
	private List<Set> tasks;
	private List<RunnerState> runners;
	private HashMap<String, Location> loc_map;
	private RuleEngine re;
	private MainFrame mf;
	/*
	 * add extra property support
	 */
	private Properties props;
	
	@Override
	protected void setup() {
		Object[] args = this.getArguments();
		super.setup();
		wsTestCases = new HashMap<String, Set>();
		suite = null;
		props = new Properties();
		tasks = new ArrayList<Set>();
		runners = new ArrayList<RunnerState>();
		loc_map = new HashMap<String, Location>();
		// TODO
		re = new RuleEngine((String)args[2]);
		String suite_directory = (String)args[0];
		String case_directory = (String)args[1];
		mf = (MainFrame)args[3];
		this.QueryLocationsWithAMS();
		this.addBehaviour(new CoorParseTaskBehav(case_directory, suite_directory, this));
		this.addBehaviour(new CoorInterpreter(this));
		
		
		
		
		/********************/
		/*this.addBehaviour(new CoorGernerateRunnerBehav(this, 2));
		ArrayList<String> lst = new ArrayList<String>();
		lst.add("Runner0");
		lst.add("Runner1");
		TestTask entity = new TestTask("case1", "http://166.111.134.183:8080/SOAservice/services/HelloWorld?wsdl",
			"multiply", "INT(8)", "INT", "");
		entity.addProperty("complexity", new Integer(1));
		entity.setThreadCount(3);
		this.addBehaviour(new CommonSendObjMsgBehav(entity, lst, Constants.TASK_ARRIVE_MSG_EXT, ACLMessage.INFORM, this));*/
		/********************/
		
		// this.addBehaviour(new CommonSendObjMsgBehav(null));
		// this.addBehaviour(new ReceiveMsgBehavTest(this));
		// this.addBehaviour(new SendMsgBehavTest("", "", this));
	}

	@Override
	protected void takeDown() {
		// TODO
		super.takeDown();
	}
	
	public synchronized void addTestCase(String category, TestCase ws_case) throws CaseNameConflictException{
		if (wsTestCases.containsKey(category)) {
			Set case_set = wsTestCases.get(category);
			case_set.add(ws_case);
		} else {
			HashSet<TestCase> case_set = new HashSet<TestCase>();
			case_set.add(ws_case);
			wsTestCases.put(category, case_set);
		}
	}
	
	public synchronized Set getCaseSetByCategory(String category) {
		return wsTestCases.get(category);
	}

	public synchronized void setTestSuite(TestSuite _suite) {
		suite = _suite;
	}

	public synchronized TestSuite getSuite() {
		return suite;
	}

	public synchronized void addRunner(RunnerState _runner) {
		runners.add(_runner);
	}

	public synchronized List<RunnerState> getRunners() {
		return runners;
	}

	public synchronized void addProperty(String key, Object value) {
		props.put(key, value);
	}
	
	public synchronized Object getProperty(String key) {
		return props.get(key);
	}
	
	private void QueryLocationsWithAMS() {
		this.getContentManager().registerLanguage(new SLCodec());
		this.getContentManager().registerOntology(MobilityOntology.getInstance());
		ACLMessage request = new ACLMessage(ACLMessage.REQUEST);
		request.setLanguage(new SLCodec().getName());
		request.setOntology(MobilityOntology.getInstance().getName());
		try {
			this.getContentManager().fillContent(request, new Action(this.getAMS(), new QueryPlatformLocationsAction()));
			request.addReceiver(this.getAMS());
			send(request);
			ACLMessage response = blockingReceive();
			ContentElement ce = getContentManager().extractContent(response);
			Result result = (Result) ce;
			jade.util.leap.Iterator it = result.getItems().iterator();
			while (it.hasNext()) {
				Location loc = (Location)it.next();
				if (loc != null) {
					loc_map.put(loc.getName(), loc);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public Location getLocationByIP(String ip) {
		return loc_map.get(ip);
	}
	
	public RuleEngine getRuleEngine() {
		return re;
	}
	
	public MainFrame getMainFrame() {
		return mf;
	}
	
}
